package net.trevize.pascalvoc;

import java.awt.Dimension;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URI;
import java.util.List;
import java.util.Vector;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import net.trevize.datasetexplorer.DatasetExplorerProperties;
import net.trevize.galatee.Galatee;
import net.trevize.galatee.GalateeProperties;
import net.trevize.pascalvoc.annotation.jaxb.Annotation;
import net.trevize.pascalvoc.annotation.jaxb.Filename;

import org.apache.commons.codec.digest.DigestUtils;

/**
 * 
 * 
 * @author Nicolas James <nicolas.james@gmail.com> [[http://njames.trevize.net]]
 *         PascalVOCBrowser.java - Jun 30, 2010
 */

public class PascalVOCBrowser {

	private String serialized_v_uri_jobj_filepath;
	private String serialized_v_object_jobj_filepath;

	private Galatee galatee;
	private Vector<URI> v_uri;
	private Vector<Vector<Object>> v_object;

	private String pascalvoc_path;

	public void initGalatee(String pascalvoc_path) {
		this.pascalvoc_path = pascalvoc_path;
		String md5_pascalvoc_path = DigestUtils.md5Hex(pascalvoc_path);

		serialized_v_uri_jobj_filepath = GalateeProperties
				.getTemporary_directory()
				+ File.separator
				+ md5_pascalvoc_path
				+ "_"
				+ DatasetExplorerProperties
						.getPascalvoc_serialized_v_uri_jobj_filename();

		serialized_v_object_jobj_filepath = GalateeProperties
				.getTemporary_directory()
				+ File.separator
				+ md5_pascalvoc_path
				+ "_"
				+ DatasetExplorerProperties
						.getPascalvoc_serialized_v_object_jobj_filename();

		if (new File(serialized_v_uri_jobj_filepath).exists()
				&& new File(serialized_v_uri_jobj_filepath).exists()) {
			loadGalateeInputsJObj();
		} else {
			createGalateeInputsJobj();
		}

		galatee = new Galatee(v_uri, v_object, new Dimension(
				GalateeProperties.getImage_width(),
				GalateeProperties.getImage_height()),
				GalateeProperties.getDescription_width(),
				GalateeProperties.getNumber_of_column());

		galatee.addGalateeListener(new GListenerImpl());
		galatee.enableSearchFunctionality();
	}

	private void createGalateeInputsJobj() {
		String annotations_path = pascalvoc_path + File.separator
				+ DatasetExplorerProperties.getPascalvoc_annotations_subdir();

		String images_path = pascalvoc_path + File.separator
				+ DatasetExplorerProperties.getPascalvoc_jpgimages_subdir();

		// create the JAXBContext.
		JAXBContext jaxb_context = null;
		try {
			jaxb_context = JAXBContext
					.newInstance("net.trevize.pascalvoc.annotation.jaxb");
		} catch (JAXBException e) {
			e.printStackTrace();
		}

		// instantiate an Unmarshaller.
		Unmarshaller u = null;
		try {
			u = jaxb_context.createUnmarshaller();
		} catch (JAXBException e) {
			e.printStackTrace();
		}

		// get all the annotation XML files.
		File[] annotations_file = new File(annotations_path).listFiles();

		v_uri = new Vector<URI>();
		v_object = new Vector<Vector<Object>>();

		for (File f : annotations_file) {
			// create an XMLStreamReader on the annotation file.
			XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
			XMLStreamReader xmlsr = null;
			try {
				xmlsr = xmlInputFactory
						.createXMLStreamReader(new FileInputStream(f));
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			} catch (XMLStreamException e1) {
				e1.printStackTrace();
			}

			// load the annotation.
			Annotation annotation = null;
			try {
				annotation = (Annotation) u.unmarshal(xmlsr);
			} catch (JAXBException e) {
				e.printStackTrace();
			}

			String filename = null;
			StringBuffer text_description = new StringBuffer(); // textual
																// description
																// for the
																// Galatee
																// browser, the
																// first element
																// in the data
																// list of each
																// image.
			Vector<net.trevize.pascalvoc.annotation.jaxb.Object> annotation_object_list = new Vector<net.trevize.pascalvoc.annotation.jaxb.Object>(); // the
																																						// second
																																						// element
																																						// of
																																						// each
																																						// image
																																						// (the
																																						// list
																																						// of
																																						// her
																																						// annotated
																																						// objects).

			List<Serializable> annotation_content = annotation.getContent(); // like
																				// we
																				// have
																				// a
																				// XSD
																				// choice
																				// element
																				// in
																				// the
																				// XSD,
																				// we
																				// can't
																				// get
																				// directly
																				// the
																				// XML
																				// elements
																				// we
																				// specifically
																				// want.
			for (Object o : annotation_content) {
				if (o instanceof Filename) {
					filename = ((Filename) o).getContent();
				}

				else

				if (o instanceof net.trevize.pascalvoc.annotation.jaxb.Object) {
					net.trevize.pascalvoc.annotation.jaxb.Object annotation_object = (net.trevize.pascalvoc.annotation.jaxb.Object) o;

					text_description.append(annotation_object.getName()
							.getContent() + "\n");

					annotation_object_list.add(annotation_object);
				}
			}

			// we add the URI to the list of the URI for the Galatee browser.
			v_uri.add(new File(images_path + File.separator + filename).toURI());

			// prepare the data for this image: we add the two elements (the
			// textual description and the list of annotated objects).
			Vector<Object> v = new Vector<Object>();
			v.add(filename + "\n" + text_description.toString()); // the textual
																	// description.
			v.add(annotation_object_list); // the list of annotated objects.

			v_object.add(v); // add the data vector to the list of the data for
								// the Galatee browser.
		}

		// serialize the Galatee inputs.

		// serialize image URI list.
		try {
			FileOutputStream fos = new FileOutputStream(
					serialized_v_uri_jobj_filepath);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(v_uri);
			oos.flush();
			oos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// serialize image data list.
		try {
			FileOutputStream fos = new FileOutputStream(
					serialized_v_object_jobj_filepath);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(v_object);
			oos.flush();
			oos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void loadGalateeInputsJObj() {
		// deserialize the image URI list.
		try {
			FileInputStream fis = new FileInputStream(
					serialized_v_uri_jobj_filepath);
			ObjectInputStream ois = new ObjectInputStream(fis);
			v_uri = (Vector<URI>) ois.readObject();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		// deserialize the image data list.
		try {
			FileInputStream fis = new FileInputStream(
					serialized_v_object_jobj_filepath);
			ObjectInputStream ois = new ObjectInputStream(fis);
			v_object = (Vector<Vector<Object>>) ois.readObject();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public Galatee getGalatee() {
		return galatee;
	}

}
